package com.baicaoyuan.web.service;

import com.baicaoyuan.web.common.MsgUtil;
import com.baicaoyuan.web.common.PlatformIdConfig;
import com.baicaoyuan.web.common.TimeUtils;
import com.baicaoyuan.web.common.relation.RelationCache;
import com.baicaoyuan.web.enums.ApplyStatusEnum;
import com.baicaoyuan.web.enums.LevelEnum;
import com.baicaoyuan.web.enums.ProjectBusinessEnum;
import com.baicaoyuan.web.enums.ProjectStatusEnum;
import com.baicaoyuan.web.model.*;
import com.baicaoyuan.web.repository.JzzUserProjectRepository;
import com.baicaoyuan.web.repository.ProjectItemRepository;
import com.baicaoyuan.web.repository.ProjectItemUserRepository;
import com.baicaoyuan.web.repository.ProjectRepository;
import com.baicaoyuan.web.request.br.*;
import com.baicaoyuan.web.response.ProjectItemResponse;
import com.baicaoyuan.web.response.ProjectItemUserMsgResponse;
import com.baicaoyuan.web.response.ProjectItemUserResponse;
import com.baicaoyuan.web.response.ProjectResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ProjectService {

    @Autowired
    ProjectRepository projectRepository;

    @Autowired
    ProjectItemRepository projectItemRepository;

    @Autowired
    ScoreDetailService scoreDetailService;

    @Autowired
    ProjectItemUserRepository projectItemUserRepository;

    @Autowired
    UserService userService;

    @Autowired
    PlatformIdConfig platformIdConfig;

    @Autowired
    JzzService jzzService;

    @Autowired
    RelationCache relationCache;

    @Autowired
    JzzUserProjectRepository jzzUserProjectRepository;

    @Transactional(rollbackFor = Exception.class)
    public void saveProject(BProjectRequest request) {
        ProjectDO project = new ProjectDO();
        BeanUtils.copyProperties(request, project);

        List<ProjectItemDO> items = new ArrayList<>();

        request.getProjectItems().stream().forEach(x -> {
            ProjectItemDO item = new ProjectItemDO();
            BeanUtils.copyProperties(x, item);
            items.add(item);
        });

        project.setCreateTime(TimeUtils.getCurrentTime());
        project.setStatus(ProjectStatusEnum.NORMAL.getStatus());
        ProjectDO proj = projectRepository.save(project);

        Objects.requireNonNull(proj);

        items.stream().forEach(x -> {
            x.setProjectFk(proj.getId());
            x.setStatus(ProjectStatusEnum.NORMAL.getStatus());
            projectItemRepository.save(x);
        });
    }

    public void editProject(BProjectEditRequest request) {
        ProjectDO proj = this.projectRepository.findOne(request.getId());
        BeanUtils.copyProperties(request, proj);
        Objects.requireNonNull(this.projectRepository.save(proj));
    }

    public void saveProjectItem(BProjectItemRequest request) {
        ProjectItemDO pi = new ProjectItemDO();
        BeanUtils.copyProperties(request, pi);
        pi.setStatus(ProjectStatusEnum.NORMAL.getStatus());

        Objects.requireNonNull(this.projectItemRepository.save(pi));
    }

    public void editProjectItem(BProjectItemEditRequest request) {
        ProjectItemDO pi = this.projectItemRepository.findOne(request.getId());
        BeanUtils.copyProperties(request, pi);
        Objects.requireNonNull(this.projectItemRepository.save(pi));
    }

    /**
     * 修改项目状态
     *
     * @param projectId
     * @param status
     */
    public void updateProjectStatus(Long projectId, ProjectStatusEnum status) {
        this.projectRepository.updateStatus(projectId, status.getStatus());
    }

    public void updateProjectItemStatus(Long projectItemId, ProjectStatusEnum status) {
        this.projectItemRepository.updateStatus(projectItemId, status.getStatus());
    }

    /**
     * 获取项目列表
     *
     * @return
     */
    public List<ProjectResponse> getProjects() {
        List<ProjectResponse> result = new ArrayList<>();
        List<ProjectDO> list = projectRepository.findByStatusIsNot(ProjectStatusEnum.DELETE.getStatus());
        list.stream().forEach(x -> {
            result.add(toProjectResponse(x));
        });
        return result;
    }

    /**
     * 获取单个项目详情
     *
     * @param id
     * @return
     */
    public ProjectResponse getProject(Long id) {
        ProjectDO project = projectRepository.getOne(id);
        return toProjectResponse(project);
    }

    /**
     * 获取项目下的业务列表
     *
     * @param projectId
     * @return
     */
    public List<ProjectItemResponse> getProjectItems(Long projectId, Long userId) {

        List<ProjectItemResponse> result = new ArrayList<>();
        List<ProjectItemDO> list = projectItemRepository.findByProjectFkAndStatusNot(projectId, ProjectStatusEnum.DELETE.getStatus());
        //信用卡
        final List<BigInteger> projectItemIds = projectId == 2 ? findByProjectIdAndUserIdAndStatus(projectId, userId) : null;

        list.stream().forEach(x -> {
            ProjectItemResponse r = toProjectItemResponse(x);
            if (projectId == 2 && projectItemIds != null) {
                r.setCanApply(!projectItemIds.contains(BigInteger.valueOf(x.getId())));
            }
            result.add(r);
        });
        return result;
    }

    public boolean checkCardCanApply(Long projectItemId, Long userId) {
        //信用卡
        final List<BigInteger> projectItemIds = findByProjectIdAndUserIdAndStatus(2L, userId);
        return projectItemIds.contains(BigInteger.valueOf(projectItemId));
    }

    private List<BigInteger> findByProjectIdAndUserIdAndStatus(Long projectId, Long userId) {
        return this.projectItemUserRepository.findByProjectIdAndUserIdAndStatus(projectId, userId, ApplyStatusEnum.SCORE.getStatus());
    }

    public boolean perfectProjectItem(BProjectItemApplyPerfectRequest request) throws Exception {
        ProjectItemUserDO piu = projectItemUserRepository.findOne(request.getProjectItemUserId());
        if (!request.getUserId().equals(piu.getUserId())) {
            throw new Exception("非法数据！");
        }
        BeanUtils.copyProperties(request, piu);
        return projectItemUserRepository.save(piu) != null;
    }

    /**
     * 申请业务
     *
     * @param request
     */
    public ProjectItemUserDO applyProjectItem(BProjectItemApplyRequest request) {

        ProjectItemUserDO piu = new ProjectItemUserDO();
        BeanUtils.copyProperties(request, piu);

        UserDO user = this.userService.findOne(request.getUserId());
        piu.setUserName(user.getUserName());
        piu.setTelephone(user.getTelephone());
        piu.setCreateTime(TimeUtils.getCurrentTime());
        piu.setStatus(ApplyStatusEnum.COMMIT.getStatus());

        ProjectDO project = projectRepository.getOne(request.getProjectId());

        piu.setProjectName(project.getName());
        piu.setContributionValue(project.getContributionValue());
        piu.setPercent(project.getPercentPlatform() + ":" + project.getPercentPerson() + ":" + project.getPercentIndirect() + ":" + project.getPercentDirect() + ":" + project.getPercentMe());

        ProjectItemDO pi = projectItemRepository.getOne(request.getProjectItemId());
        piu.setProjectItemName(pi.getBusinessName());
        Long score = pi.getScore();
        piu.setScore(score);
        BigDecimal platform = percentToScore(score, project.getPercentPlatform());
        BigDecimal person = percentToScore(score, project.getPercentPerson());
        BigDecimal indirect = percentToScore(score, project.getPercentIndirect());
        BigDecimal direct = percentToScore(score, project.getPercentDirect());
        BigDecimal me = percentToScore(score, project.getPercentMe());
        piu.setPercentScore(platform.doubleValue() + ":" + person.doubleValue() + ":" + indirect.doubleValue() + ":" + direct.doubleValue() + ":" + me.doubleValue());
        ProjectItemUserDO piud = projectItemUserRepository.save(piu);
        Objects.requireNonNull(piud);

        MsgUtil.apply(piu.getTelephone(), piu.getProjectItemName());
        MsgUtil.applyToAdmin(piu.getTelephone(), piu.getProjectItemName(), platformIdConfig.getTelephone());
        return piud;
    }

    private BigDecimal percentToScore(Long score, Long percent) {
        return BigDecimal.valueOf(((double) (score * percent)) / 100);
    }

    /**
     * 审核业务
     *
     * @param projectItemUserId 申请id
     * @param status            状态
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateProjectItemUserStatus(Long projectItemUserId, String status, List<String> serialNumber, String rejectReason) throws Exception {
        Integer result = projectItemUserRepository.updateStatus(projectItemUserId, status, rejectReason);
        if (result <= 0) {
            throw new RuntimeException();
        }

        //如果审核结果为获得积分，则对业务办理人和直接介绍人加贡献分
        ProjectItemUserDO piu = projectItemUserRepository.findOne(projectItemUserId);
        ProjectDO proj = projectRepository.findOne(piu.getProjectId());


        //如果是jzz的话， 不参与积分的获取了。
        if (proj.getJoinJzz() == 1 && ApplyStatusEnum.SUCCESS.getStatus().equals(status)) {
            if (!CollectionUtils.isEmpty(serialNumber)) {
                Collection<String> collection = serialNumber.stream().distinct().collect(Collectors.toList());
                for (String sn : collection) {
                    JzzUserProjectDO userProject = jzzUserProjectRepository.findBySerialNumber(sn);
                    if (userProject != null) {
                        throw new Exception(String.format("设备序列号: %s 已绑定金种子用户id：%s ", userProject.getSerialNumber(), userProject.getUserId().toString()));
                    }
                    jzzService.createJzzUser(piu.getUserId(), proj.getId(), sn);
                }
                relationCache.add(piu.getUserId());
            } else {
                throw new Exception("金种子用户审核需要设备的序列号");
            }
        }

        /**
         * 成功办理业务，设置为vip， 如果直接介绍人不是vip，则也设置成vip
         */
        if (proj.getJoinJzz() == 0 && ApplyStatusEnum.SUCCESS.getStatus().equals(status)) {
            userService.setVip(piu.getUserId());
            userService.contributeValuePlus(piu.getUserId(), proj.getContributionValue() == null ? BigDecimal.ZERO : proj.getContributionValue());
        }

        /**
         *  获得积分(金种子项目不参与积分奖励)
         */
        if (proj.getJoinJzz() == 0 && ApplyStatusEnum.SCORE.getStatus().equals(status)) {
            scorePlus(piu.getId());
        }
    }

    /**
     * 计算各方所得积分
     *
     * @param projectUserItemId
     */
    @Transactional(rollbackFor = Exception.class)
    void scorePlus(Long projectUserItemId) {

        ProjectItemUserDO piu = this.projectItemUserRepository.findOne(projectUserItemId);

        String[] percentScore = piu.getPercentScore().split(":");
        BigDecimal scorePlatform = BigDecimal.valueOf(Double.parseDouble(percentScore[0]));
        BigDecimal scorePerson = BigDecimal.valueOf(Double.parseDouble(percentScore[1]));
        BigDecimal scoreIndirect = BigDecimal.valueOf(Double.parseDouble(percentScore[2]));
        BigDecimal scoreDirect = BigDecimal.valueOf(Double.parseDouble(percentScore[3]));
        BigDecimal scoreMe = BigDecimal.valueOf(Double.parseDouble(percentScore[4]));

        Long platformId = platformIdConfig.getPlatformId();

        this.userService.scorePlus(platformId, scorePlatform);
        if (scorePlatform.compareTo(BigDecimal.ZERO) == 1) {
            scoreDetailService.save(platformId, "", scorePlatform, piu, LevelEnum.PLATFORM);
        }

        ProjectDO proj = projectRepository.findOne(piu.getProjectId());
        if (ProjectBusinessEnum.COOPERATIVE.getStatus().equals(proj.getCategory())) {
            this.userService.scorePlus(proj.getUserFk(), scorePerson);
            if (scorePerson.compareTo(BigDecimal.ZERO) == 1) {
                scoreDetailService.save(proj.getUserFk(), "", scorePerson, piu, LevelEnum.PARTNER);
            }
        }

        UserDO me = this.userService.findOne(piu.getUserId());

        //办理人获取积分并且保存明细
        this.userService.scorePlus(me.getId(), scoreMe);
        MsgUtil.checkGetScoreMe(piu.getProjectItemName(), me.getTelephone(), scoreMe);

        //保存积分明细
        if (scoreMe.compareTo(BigDecimal.ZERO) == 1) {
            scoreDetailService.save(me.getId(), "", scoreMe, piu, LevelEnum.Me);
        }

        //直推用户获取积分并且保存明细，若无直推用户，则计入平台
        Long directId = me.getUserDirectId() != null ? me.getUserDirectId() : platformId;
        this.userService.scorePlus(directId, scoreDirect);

        //保存积分明细
        if (scoreDirect.compareTo(BigDecimal.ZERO) == 1) {
            scoreDetailService.save(directId, "", scoreDirect, piu, LevelEnum.DIRECT);
            //发送短信
            if (me.getUserDirectId() != null) {
                UserDO userDirect = this.userService.findOne(me.getUserDirectId());
                MsgUtil.checkGetScoreDirect(piu.getProjectItemName(), userDirect.getTelephone(), scoreDirect);
            }
        }

        //间推用户获取积分并且保存明细，若无间推用户，则计入平台
        Long indirectId = me.getUserIndirectId() != null ? me.getUserIndirectId() : platformId;
        this.userService.scorePlus(indirectId, scoreIndirect);
        //保存积分明细
        if (scoreIndirect.compareTo(BigDecimal.ZERO) == 1) {
            scoreDetailService.save(indirectId, "", scoreIndirect, piu, LevelEnum.INDIRECT);
            //发送短信
            if (me.getUserIndirectId() != null) {
                UserDO userInDirect = this.userService.findOne(me.getUserIndirectId());
                MsgUtil.checkGetScoreIndirect(piu.getProjectItemName(), userInDirect.getTelephone(), scoreIndirect);
            }
        }
    }

    /**
     * 获取后业务申请列表
     *
     * @param projectItemId 项目id
     * @return
     */
    public List<ProjectItemUserResponse> getProjectItemUsers(Long projectItemId) {
        List<ProjectItemUserResponse> result = new ArrayList<>();
        List<ProjectItemUserDO> list = this.projectItemUserRepository.findByProjectItemIdAndStatusIsNotOrderByCreateTimeDesc(projectItemId, ApplyStatusEnum.DELETED.getStatus());
        list.stream().forEach(x -> {
            result.add(toProjectItemUserResponse(x));
        });
        return result;
    }

    public List<ProjectItemUserResponse> getProjectItemUsersByUserId(Long userId) {
        List<ProjectItemUserDO> list = this.projectItemUserRepository.findByUserIdOrderByCreateTimeDesc(userId);
        List<ProjectItemUserResponse> result = new ArrayList<>();
        list.stream().forEach(x -> {
            ProjectItemUserResponse response = toProjectItemUserResponse(x);

            result.add(response);
        });
        return result;
    }

    public List<ProjectItemUserMsgResponse> getTopProjectItemUsers(Integer top) {
        PageRequest pageRequest = new PageRequest(0, top);
        List<String> status = Arrays.asList(ApplyStatusEnum.SCORE.getStatus(), ApplyStatusEnum.SUCCESS.getStatus());
        List<ProjectItemUserDO> list = this.projectItemUserRepository.findByStatusInOrderByCreateTimeDesc(status, pageRequest);

        List<ProjectItemUserMsgResponse> result = new ArrayList<>();
        list.forEach(x -> {
            result.add(toProjectItemUserMsgResponse(x));
        });

        return result;
    }

    public ProjectItemUserMsgResponse toProjectItemUserMsgResponse(ProjectItemUserDO projectItemUserDO) {
        ProjectItemUserMsgResponse response = new ProjectItemUserMsgResponse();
        BeanUtils.copyProperties(projectItemUserDO, response);
        return response;
    }

    public ProjectItemUserResponse toProjectItemUserResponse(ProjectItemUserDO projectItemUserDO) {
        ProjectItemUserResponse projectItemUserResponse = new ProjectItemUserResponse();
        BeanUtils.copyProperties(projectItemUserDO, projectItemUserResponse);
        if (projectItemUserResponse.getUserId() != null) {
            UserDO user = userService.findOne(projectItemUserResponse.getUserId());
            String telephone = user.getTelephone();
            projectItemUserResponse.setTelephone(telephone);
            projectItemUserResponse.setRealName(user.getRealName());
        }
        ProjectDO project = projectRepository.findOne(projectItemUserDO.getProjectId());
        projectItemUserResponse.setJoinJzz(project.getJoinJzz());
        return projectItemUserResponse;
    }

    private ProjectItemResponse toProjectItemResponse(ProjectItemDO projectItemDO) {
        ProjectItemResponse projectItemResponse = new ProjectItemResponse();
        BeanUtils.copyProperties(projectItemDO, projectItemResponse);
        return projectItemResponse;
    }

    private ProjectResponse toProjectResponse(ProjectDO projectDO) {
        ProjectResponse projectResponse = new ProjectResponse();
        BeanUtils.copyProperties(projectDO, projectResponse);
        return projectResponse;
    }

    /**
     * 设置项目是否参与金种子
     *
     * @param id
     * @return
     */
    public boolean joinJzz(Long id) {
        return projectRepository.updateJoinJzz(id, 1) > 0;
    }
}
